/*
	It started to be written by Roosevelt de Lima Sardinha, in March, 17th, 2010.
	Rootabs is a javascript component for creating and managing tabs in a web page.
*/
function rootabs(id, properties)
{
	var rtabs = this;

	// Checking if id is valid.
	if (id == null)
	{
		document.write("rootabs: id cannot be null");
	}
	else
	{
		this.id = properties.id;
	}
	
	// CSS configuration
	this.panelsCSS = properties.panelsCSS ? properties.panelsCSS : 'default-panels-css';
	this.tabsCSS = properties.tabsCSS ? properties.tabsCSS : 'default-tabs-css';
	this.tabsSelectedCSS = properties.tabsSelectedCSS ? properties.tabsSelectedCSS : 'default-tabs-selected-css';
	this.navigationRightCSS = properties.navigationRightCSS ? properties.navigationRightCSS : 'default-navigation-right';
	this.navigationLeftCSS = properties.navigationLeftCSS ? properties.navigationLeftCSS : 'default-navigation-left';
	this.navigationCenterCSS = properties.navigationCenterCSS ? properties.navigationCenterCSS : 'default-navigation-center';
	this.horizontal = properties.horizontal ? properties.horizontal : true;
	this.vertical = properties.vertical ? properties.vertical : false; 
	
	this.height = properties.height ? properties.height : '300';
	this.width = properties.width ? properties.width : '600';
	this.navigationEnabled = properties.navigationEnabled ? properties.navigationEnabled : true;
	this.navigationStep = properties.navigationStep ? properties.navigationStep : 40;
	this.tabPrefix = properties.tabPrefix ? properties.tabPrefix : 'tab-';
		
	selected = null;	
	
	//Panels Array
	this.panels = new Array();
	
	//LIs array
	this.tabs = new Array()
	
	this.container = document.createElement('div');
	this.ul = document.createElement('ul');
	this.navigationCenter = document.createElement('div');
	this.navigationCenter.style.width = '1px';
	this.navigationCenter.className = this.navigationCenterCSS;
	this.navigationLeft = document.createElement('div');
	this.navigationLeft.className = this.navigationLeftCSS;
	this.navigationRight = document.createElement('div');
	this.navigationRight.className = this.navigationRightCSS;
	
	// Initial CSS configurations. Default behaviour.
	this.navigationLeft.style.display = 'none';
	this.navigationRight.style.display = 'none';
	this.container.style.overflow = 'hidden';
	this.container.style.position = 'relative';
	
	this.ul.className = 'default-ul';
	
	// Add elements to the container
	this.navigationCenter.appendChild(this.ul);
	this.container.appendChild(this.navigationLeft);
	this.container.appendChild(this.navigationRight);
	this.container.appendChild(this.navigationCenter);
	
	// Set navigation arrows behaviour
	this.navigationLeft.onclick = function(){
		rtabs.scrollLeft(rtabs.navigationStep);
	}
	this.navigationRight.onclick = function(){
		rtabs.scrollRight(rtabs.navigationStep);
	}
	
	this.setNavigationRightCSS = function(nameOfClass)
	{
		this.navigationRight.className = nameOfClass;
	}	
	
	this.setNavigationLeftCSS = function(nameOfClass)
	{
		this.navigationLeft.className = nameOfClass;
	}
	
	this.setNavigationCenterCSS = function(nameOfClass)
	{
		this.navigationCenter.className = nameOfClass;
	}
	
	this.enableNavigation = function(status)
	{
		if (status == true)
		{
			this.navigationLeft.style.display = '';
			this.navigationRight.style.display = '';
		}
		else
		{
			this.navigationLeft.style.display = 'none';
			this.navigationRight.style.display = 'none';
		}
		this.navigationEnabled = status;
	}
	
	this.tabBarOverflow = function ()
	{
		// Check if the tabs take more space than its reserved to it. I call this a tab overflow here.
		var ulLeft = this.ul.offsetLeft;
		var containerLeft =  this.container.offsetLeft - 5;
		var ulRight = ulLeft + this.ul.offsetWidth;
		var containerRight = containerLeft + this.container.offsetWidth;
		
		// left overflow
		if((containerLeft > ulLeft) && (containerRight >= ulRight)) 
		{
			return 0;
		}	
	
		// right overflow
		if((containerLeft <= ulLeft) && (containerRight < ulRight))
		{
			return 1;
		}
			
		// left and right overflow	
		if((containerLeft > ulLeft) && (containerRight < ulRight))
		{
			return 2;
		}
		
		// no overflow
		return -1;
	}
	
	function refreshNavigationBar()
	{
		var overflow = rtabs.tabBarOverflow();
		
		switch (overflow)
		{	
			case 0:
				rtabs.navigationRight.style.display = 'none';
				rtabs.navigationLeft.style.display = '';
				break;
			case 1:
				rtabs.navigationRight.style.display = '';
				rtabs.navigationLeft.style.display = 'none';
				break;
			case 2:
				rtabs.navigationRight.style.display = '';
				rtabs.navigationLeft.style.display = '';		
				break;
			case -1:
				rtabs.navigationRight.style.display = 'none';
				rtabs.navigationLeft.style.display = 'none';			
				break;
		}
	}
	
	this.scrollLeft = function(step)
	{
		this.ul.style.position = 'relative';
		this.ul.style.left = (this.ul.offsetLeft + step) + 'px';

		refreshNavigationBar();
	}
	
	this.scrollRight = function(step)
	{
		this.ul.style.position = 'relative';
		this.ul.style.left = (this.ul.offsetLeft - step) + 'px';
		
		refreshNavigationBar();
	}
	
	this.setPanelsCSS = function(nameOfClass)
	{
		// Sets the CSS classes of all panels to the class named in the arguments. 
		for (var i = 0; i < this.panels.length; i++)			
		{
			panels[i].className = this.panelsCSS;
		}
	}
	
	this.setTabsCSS = function(nameOfClass)
	{
		// Sets the CSS classes of all tabs to the class named in the arguments.
		for (var i = 0; i < this.tabs.length; i++)			
		{
			tabs[i].className = this.tabsCSS;
		}
	}
	
	this.setHeight = function(height)
	{
		// Sets the height of the component.
		this.container.style.height = height;
		this.height = height;
	}
	this.setHeight(this.height);
	
	this.setWidth = function(width)
	{
		// Sets the width of the component.
		this.container.style.width = width;
		this.width = width;
	}
	this.setWidth(this.width);
	
	this.appendTo = function(parent)
	{
		// Appends this component to another container. Probably a div.
		parent.appendChild(this.container);
		
		this.onAppendTo(this.container);
	}
	
	function areThereEnoughTabs()
	{
		var lenTabs = rtabs.tabs.length;
		if (lenTabs > 0)
		{
			var maxNumberOfTabs = Math.floor(rtabs.container.offsetWidth / rtabs.tabs[0].tab.offsetWidth);
			if (lenTabs > maxNumberOfTabs)
			{
				return true;
			}		
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}
	
	function sumLiWidth(){
		var sumLiWidth = 0;
		var tabLength = rtabs.tabs.length;
		for (var i = 0; i < tabLength; i++)
		{
			sumLiWidth += rtabs.tabs[i].tab.offsetWidth;
		}
		return sumLiWidth;
	}
	
	var index = 0;
	this.add = function(title, position)
	{
		// Adds a new tab to this component. This tab is going to be named 'title' and it's gonna be inserted before the element at the position passed as an argument.
		if(title == null)
		{
			title = 'tab';
		}
		
		if((position == null) || (position > this.tabs.length))
		{
			position = this.tabs.length;
		}	
								
		var newTab = new tab(this.tabPrefix + index, {
			title: title, 
			tabCSS: this.tabsCSS, 
			tabSelectedCSS: this.tabSelectedCSS,
			panelCSS: this.panelsCSS
		});
		index++;
	
		if ((this.tabs.length != 0) && (position != this.tabs.length))
		{			
			var nextDOM = this.tabs[position].tab;
			this.ul.insertBefore(newTab.tab, nextDOM);
			this.tabs.splice(position, 0, newTab);			
		}
		else
		{
			this.tabs.push(newTab);
			this.ul.appendChild(newTab.tab);
			this.select(newTab.id);
			selected = newTab.id;
		}		
		this.container.appendChild(newTab.panel);

		// Check if tabs are aligned horizontally
		if (this.horizontal)
		{
			var width = sumLiWidth();
			if ((width) > this.container.offsetWidth)
			{
				this.navigationCenter.style.width = width + 'px';
				this.ul.style.width = this.navigationCenter.style.width;	
			}
			else
			{
				this.navigationCenter.style.width = this.container.offsetWidth + 'px';
				this.ul.style.width	= this.container.offsetWidth + 'px';
			}
		}
		
		// Check if tabs are aligned vertically
		if (this.vertical)
		{
			//TODO
			this.navigationCenter.style.height = this.navigationCenter.offsetHeight + newTab.tab.offsetHeight + 'px';
			this.ul.style.height = this.navigationCenter.style.height;
		}
		
		if (areThereEnoughTabs())
		{
			this.enableNavigation(true);
		}
		
		// Select it on click
		newTab.tab.onclick = function(){
			rtabs.select(newTab.id);
		}
		
		this.onAdd(newTab);
		
		return newTab.id;
	}
	
	this.remove = function(number, type)
	{
		// Removes a tab, based in its position or in its id, depending of 'type'.
		this.onBeforeRemove(number, type);

		if (this.tabs.length != 0)
		{
			// Check if tabs are aligned horizontally
			if (this.horizontal)
			{		
				var width = sumLiWidth();
				if ((width) > this.container.offsetWidth)
				{
					this.ul.style.width = width - this.tabs[0].tab.offsetWidth + 'px';
					this.navigationCenter.style.width = this.ul.style.width;
				}
				else
				{
					this.navigationCenter.style.width = this.container.offsetWidth + 'px';
					this.ul.style.width	= this.container.offsetWidth + 'px';
				}
			}
			
			// Check if tabs are aligned vertically
			if (this.vertical)
			{
				this.navigationCenter.style.height = this.navigationCenter.offsetHeight - newTab.tab.offsetHeight + 'px';
				this.navigationCenter.style.height = this.ul.style.height;
			}
		}

		if (type == 0)
		{
			// Remove by id
			var position = this.getTabPosById(this.tabPrefix + number);
			this.remove(position,1);
		}
		else{
			if (type == 1)
			{
				//Remove by position
				//Selects the next tab if the selected is going to be removed.
				if (selected == this.tabs[number].id)
				{
					if (this.tabs.length != 0)
					{
						this.next();
					}
				}
				this.tabs[number].tab.parentNode.removeChild(this.tabs[number].tab);
				this.tabs[number].panel.parentNode.removeChild(this.tabs[number].panel);
				this.tabs.splice(number, 1)
			}
		}
			
		if (this.tabs.length == 0)
		{
			this.navigationCenter.style.left = '0px';
			this.ul.style.left = '0px';
			selected = null;
		}	
		
		refreshNavigationBar();

		this.onAfterRemove();
	}
	
	this.select = function(id)
	{
		if (selected == null)	
		{
			this.getTabById(id).select();
			selected = id;
		}
		else
		{
			this.getTabById(selected).unselect();
			this.getTabById(id).select();
			selected = id;
		}
		
		this.onSelect(this.getTabById(id));
	}
	
	this.getTabPosById = function(id)
	{
		// Returns the position of the tab, based on its id.
		for (var i=0; i<this.tabs.length; i++)
		{
			if(id == this.tabs[i].id)
			{
				var position = i;
				break;
			}
		}
		return position;
	}

	this.getTabById = function(id)
	{
		// Returns a tab, based on its id.
		for (var i=0; i<this.tabs.length; i++)
		{
			if(id == this.tabs[i].id)
			{
				var position = i;
				break;
			}
		}
		
		return this.tabs[position];
	}
	
	this.next = function()
	{
		// Selects the next tab.		
		this.getTabById(selected).unselect();
		
		var position = this.getTabPosById(selected);
		
		if(position != (this.tabs.length - 1)) 
		{
			this.tabs[position + 1].select();
			selected=this.tabs[position+1].id;
		}
		else
		{
			this.tabs[0].select();
			selected=this.tabs[0].id;
		}
				
		this.onMoveNext(position);
	}
	
	this.previous = function()
	{
		// Selects the previous tab.		
		this.getTabById(selected).unselect();
		
		var position = this.getTabPosById(selected);
		if(position != 0) 
		{
			this.tabs[position - 1].select();
			selected = this.tabs[position-1].id;
		}
		else
		{
			this.tabs[this.tabs.length-1].select();
			selected=this.tabs[this.tabs.length-1].id;
		}
		
		this.onMovePrevious(position);
	}
	
	this.move = function(actualPos, newPos)
	{	
		// Moves a tab from the actual position to a new one.
		if (actualPos == newPos)
		{
			return;
		}
		var movingTab = this.tabs[actualPos];
		
		movingTabLi = movingTab.tab.parentNode.removeChild(movingTab.tab)
		movingTabPanel = movingTab.panel.parentNode.removeChild(movingTab.panel)
		
		if (newPos != (this.tabs.length - 1))
		{			
			var nextDOM = this.tabs[newPos + 1].tab;
			this.ul.insertBefore(movingTabLi, nextDOM);
		}
		else
		{
			this.ul.appendChild(movingTabLi);
		}		
		this.container.appendChild(movingTabPanel);
		
		this.tabs.splice(actualPos, 1);
		this.tabs.splice(newPos, 0, movingTab);
		
		this.onMove(movingTab, actualPos, newPos);
	}
	
	// Events
	this.onAdd = function(object){};
	this.onSelect = function(object){};
	this.onMove = function(object, actualPos, newPos){};
	this.onBeforeRemove = function(number, type){};
	this.onAfterRemove = function(){};
	this.onMoveNext = function(position){};
	this.onMovePrevious = function(position){};
	this.onAppendTo = function(object){};
}